﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Astronaut.Bot;
using Astronaut.D3;
using Astronaut.Scripts.Common;
using Astronaut.States;
using System.Text;

namespace Astronaut.Scripts
{
    /// <summary>
    /// 职业脚本核心类
    /// </summary>
    public class Core : GlobalBaseBotState
    {
        /// <summary>
        /// 脚本枚举
        /// </summary>
        private enum CoreType
        {
            #region Barbarian

            Rend,
            Hammer,
            Whirlwind,
            Debug,

            #endregion

            #region Monk

            FourInna,
            SweepingWind

            #endregion
        }

        /// <summary>
        /// 当前执行的脚本
        /// 根据上面的枚举改成对应的
        /// 枚举对应的脚本类，名字必须按照以下格式取：
        /// [职业][流派]CombatState
        /// 例如：public class BarbarianTestCombatState:CombatStateBase{}
        /// 对应的枚举就要加一个Test类型
        /// </summary>
        private CoreType CurrentCore = CoreType.SweepingWind;

        protected override void DoEnter(D3Player Entity)
        {
            var currentCombatState = (CombatStateBase)Activator.CreateInstance(Type.GetType(string.Format("Astronaut.Scripts.{0}{1}CombatState", D3Control.playerClass.ToString(), CurrentCore.ToString())));
            base.DoEnter(Entity);
            base.combatState = currentCombatState;
            D3Control.output(string.Format("{0}脚本： Ver {1}", currentCombatState.CoreName, currentCombatState.CoreVersion.ToString()));
            D3Control.output(string.Format("基类版本： Ver {0}", currentCombatState.BaseVersion.ToString()));
            D3Control.output("作者：hellsoul86");
        }
    }

    /// <summary>
    /// 野蛮人脚本演示
    /// </summary>
    public class BarbarianDebugCombatState : CombatStateBase
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public BarbarianDebugCombatState()
            : base()
        {
            //脚本名称，用于显示在脚本加载的时候日志框的文字
            base.CoreName = "Demo";
            //脚本版本，用于显示在脚本加载的时候日志框的文字
            base.CoreVersion = new Version(1, 0, 0);
        }

        /// <summary>
        /// 属性初始化重载
        /// </summary>
        protected override void PropertiesInit()
        {
            base.PropertiesInit();
            //自定义的初始化放这儿
            //例如，基类里定义过base.IsDebug = true了
            //这里再定义一下
            //base.IsDebug = false;
            //就变成你要的false了
            //或者追加新的定义
            //base.TimerDictionary.Add("撕裂计时器", new CWSpellTimer(2500, false)));
            //CWSpellTimer第一个是间隔时间，第二个的true/false表示是否是计时器创建的时候立即IsReady
            //一定要放在base.PropertiesInit();后面
        }

        /// <summary>
        /// 设置技能词典重载
        /// </summary>
        protected override void SetAbilityDictionary()
        {
            base.SetAbilityDictionary();
            //自定义的技能词典放这儿
            //如果要修改某技能的属性，用如下方式：
            //base.AbilityDictionary["霸气无双"] = new Ability() { SpellID = "aaa", Cost = 10, RuneName = "bbb" };
            //如果只是某个值修改，也可以这样
            //base.AbilityDictionary["霸气无双"].Cost = 20;
            //一定要放在base.SetAbilityDictionary();后面
        }

        /// <summary>
        /// 设置优先攻击目标
        /// </summary>
        protected override void SetPriorityAttackTargets()
        {
            base.SetPriorityAttackTargets();
            //如果要对基类的优先攻击列表修改，用如下方式：
            //新增一个怪进入优先列表
            //base.PriorityAttackTargets.Add(new CustomTarget() { ID = 111, Name = "我是新增的怪物" });
            //从列表中移除一个怪
            //base.PriorityAttackTargets.RemoveAll(t => t.ID == 111);
            //我不要这个列表了
            //base.PriorityAttackTargets = new List<CustomTarget>();
            //一定要放在base.SetPriorityAttackTargets();后面
        }

        /// <summary>
        /// 设置锁定攻击目标
        /// </summary>
        protected override void SetLockAttackTargets()
        {
            base.SetLockAttackTargets();
            //同SetPriorityAttackTargets()
        }

        /// <summary>
        /// 设置延迟攻击目标
        /// </summary>
        protected override void SetDelayAttackTargets()
        {
            base.SetDelayAttackTargets();
            //同SetPriorityAttackTargets()
        }

        /// <summary>
        /// 设置忽略攻击目标
        /// </summary>
        protected override void SetIgnoreAttackTargets()
        {
            base.SetIgnoreAttackTargets();
            //同SetPriorityAttackTargets()
        }

        /// <summary>
        /// 设置血线保护器列表
        /// 基类默认了2种血线保护，吃血球和吃药
        /// </summary>
        protected override void SetHealthKeeperList()
        {
            base.SetHealthKeeperList();
            //添加一个血线保护， BaseResource = 0, IsBaseResource = true, BaseResourcePlus = 0用法和castspell一样
            base.HealthKeeperList.Add(new HealthKeeper() { HpPct = 90, Ability = base.AbilityDictionary["test"], BaseResource = 0, IsBaseResource = true, BaseResourcePlus = 0 });
            //修改血球的血线保护值为60，其他一样
            base.HealthKeeperList.Find(h => h.IsHealthBall).HpPct = 60;
            //修改吃药的血线保护值为30，其他一样
            base.HealthKeeperList.Find(h => h.IsPotion).HpPct = 30;
            //排序血线保护器血线
            base.SortHealthKeeperList();
        }

        /// <summary>
        /// 攻击重载
        /// </summary>
        protected override void Attack()
        {
            //判断当前攻击的目标是否有效，并且目标距离玩家的绝对距离大于近战攻击距离或者模型距离，小于50，这些数字具体的值以及判断条件，根据技能适用范围自己设置
            //if (IsTargetValid() && D3Control.curTarget.DistanceFromPlayer <= 50 && (D3Control.curTarget.DistanceFromPlayer > MeleeRange || D3Control.curTarget.DistanceFromPlayer <= D3Control.getMobRange(D3Control.curTarget)))
            //{
            //施法，已经将3种施法函数合并成一种了
            //参数1（必填）：
            //
            //      技能实体，例如 base.AbilityDictionary["跃击"]
            //
            //参数2（选填）：
            //
            //      1. 释放的目标，可以是D3Control.curTarget，D3Control.Player
            //      2. 释放的坐标：D3Control.curTarget.Location, D3Control.Player.Location, 或者 自己造一个坐标 D3Control.getSideSpot(D3Control.curTarget.Location, D3Control.Player.Location, -5)
            //      3. 不填：那么根据技能初始化时候的定义，Location类技能目标默认是D3Control.Player, Target类和Direction类默认是D3Control.curTarget
            //
            //参数3，4，5（选填）：
            //
            //      3：使用该技能前，需要保留多少怒气，包括其他职业的资源
            //      4：使用该技能前，是否需要判断其他技能在不在冷却
            //      5：当参数4的结果是true的时候，需要额外保留的怒气，包括其他职业的资源
            //      参数3，4，5要么都不填写，他们都有自己的默认值，比如：CastSpell(base.AbilityDictionary["先祖之锤"])，要么就按照下面格式填写，否则会报错。
            //      CastSpell(base.AbilityDictionary["先祖之锤"], D3Control.curTarget, 0, base.CanCast(base.AbilityDictionary["狂战之怒"]), 30);
            //      在初始化的时候定义的计时器，看自己需求添加和使用，
            //      base.TimerDictionary["撕裂计时器"].Reset();
            //}

            //保证最后一行调用下面的东西
            //内部逻辑已经变成锁定目标相关。
            base.Attack();
        }

        /// <summary>
        /// AOE重载
        /// </summary>
        protected override void DoAoe()
        {
            //随便写点技能就是了。或者你有更好的想法。
            //CastSpell(base.AbilityDictionary["霸气无双"], D3Control.Player);
            //CastSpell(base.AbilityDictionary["撕裂"], D3Control.Player);
        }

        /// <summary>
        /// 拉怪重载
        /// </summary>
        /// <param name="target"></param>
        protected override void DoPulling(D3Unit target)
        {
            //检查Buff
            //第一个参数就是技能，第二个参数true/false表示是否cd一到就使用。
            //CheckBuff(base.AbilityDictionary["战吼"], true);
            //CheckBuff(base.AbilityDictionary["战斗暴怒"]);
            //保证最后一行调用下面的东西
            base.DoPulling(target);
        }
    }

    #region Barbarian

    /// <summary>
    /// 野蛮人撕裂流
    /// </summary>
    public class BarbarianRendCombatState : CombatStateBase
    {
        public BarbarianRendCombatState()
            : base()
        {
            base.CoreName = "野蛮人撕裂流";
            base.CoreVersion = new Version(1, 3);
        }

        /// <summary>
        /// 参数初始化
        /// </summary>
        protected override void PropertiesInit()
        {
            base.PropertiesInit();
            base.TimerDictionary.Add("撕裂计时器", new CWSpellTimer(2500));
        }

        /// <summary>
        /// 攻击重载
        /// </summary>
        protected override void Attack()
        {
            if (IsTargetValid() && D3Control.curTarget.DistanceFromPlayer <= 50 && D3Control.curTarget.DistanceFromPlayer > MeleeRange)
            {
                CastSpell(base.AbilityDictionary["跃击"], D3Control.curTarget);
            }
            if (IsTargetValid() && D3Control.curTarget.IsElite && (D3Control.curTarget.DistanceFromPlayer <= AoeRange || D3Control.curTarget.DistanceFromPlayer <= D3Control.getMobRange(D3Control.curTarget)))
            {
                CastSpell(base.AbilityDictionary["狂战之怒"], D3Control.Player);
            }
            if (IsTargetValid() && (D3Control.curTarget.DistanceFromPlayer <= AoeRange || D3Control.curTarget.DistanceFromPlayer <= D3Control.getMobRange(D3Control.curTarget)))
            {
                CastSpell(base.AbilityDictionary["霸气无双"], D3Control.Player);
            }
            if (IsTargetValid() && base.TimerDictionary["撕裂计时器"].IsReady && (D3Control.curTarget.DistanceFromPlayer <= AoeRange || D3Control.curTarget.DistanceFromPlayer <= D3Control.getMobRange(D3Control.curTarget)))
            {
                if (CastSpell(base.AbilityDictionary["撕裂"], D3Control.Player))
                {
                    base.TimerDictionary["撕裂计时器"].Reset();
                }
            }
            if (IsTargetValid())
            {
                CastSpell(base.AbilityDictionary["顺劈斩"]);
            }
            base.Attack();
        }

        /// <summary>
        /// 拉怪重载
        /// </summary>
        /// <param name="target">目标</param>
        /// <returns></returns>
        protected override void DoPulling(D3Unit target)
        {
            CheckBuff(base.AbilityDictionary["战吼"], true);
            CheckBuff(base.AbilityDictionary["战斗暴怒"]);
            base.DoPulling(target);
        }

        /// <summary>
        /// 范围攻击重载
        /// </summary>
        protected override void DoAoe()
        {
            CastSpell(base.AbilityDictionary["霸气无双"], D3Control.Player);
            CastSpell(base.AbilityDictionary["撕裂"], D3Control.Player);
        }
    }

    /// <summary>
    /// 野蛮人大锤流
    /// </summary>
    public class BarbarianHammerCombatState : CombatStateBase
    {
        public BarbarianHammerCombatState()
            : base()
        {
            base.CoreName = "野蛮人大锤流";
            base.CoreVersion = new Version(2, 7, 3);
        }

        /// <summary>
        /// 参数初始化
        /// </summary>
        protected override void PropertiesInit()
        {
            base.PropertiesInit();
            base.IsRetarget = false;
        }

        /// <summary>
        /// 攻击重载
        /// </summary>
        protected override void Attack()
        {
            if (IsTargetValid() && (D3Control.curTarget.IsElite && (D3Control.curTarget.DistanceFromPlayer <= AoeRange || D3Control.curTarget.DistanceFromPlayer <= D3Control.getMobRange(D3Control.curTarget))))
            {
                CastSpell(base.AbilityDictionary["狂战之怒"], D3Control.Player);
            }
            if (IsTargetValid())
            {
                CastSpell(base.AbilityDictionary["顺劈斩"], 20, base.CanCast(base.AbilityDictionary["先祖之锤"]), 50);
            }
            if (IsTargetValid() && (D3Control.curTarget.DistanceFromPlayer <= AoeRange || D3Control.curTarget.DistanceFromPlayer <= D3Control.getMobRange(D3Control.curTarget)))
            {
                CastSpell(base.AbilityDictionary["霸气无双"], D3Control.Player);
                if (D3Control.curTarget.DistanceFromPlayer <= MeleeRange)
                {
                    CastSpell(base.AbilityDictionary["先祖之锤"], D3Control.curTarget);
                }
                else
                {
                    var attackLocation = D3Control.getSideSpot(D3Control.Player.Location, D3Control.Player.Rotation, (int)MeleeRange);
                    CastSpell(base.AbilityDictionary["先祖之锤"], attackLocation);
                }
            }
            base.Attack();
        }

        /// <summary>
        /// 拉怪重载
        /// </summary>
        /// <param name="target">目标</param>
        /// <returns></returns>
        protected override void DoPulling(D3Unit target)
        {
            CheckBuff(base.AbilityDictionary["战吼"], true);
            CheckBuff(base.AbilityDictionary["战斗暴怒"]);
            base.DoPulling(target);
        }

        /// <summary>
        /// 范围攻击重载
        /// </summary>
        protected override void DoAoe()
        {
            CastSpell(base.AbilityDictionary["霸气无双"], D3Control.Player);
            if (IsTargetValid())
            {
                if (D3Control.curTarget.DistanceFromPlayer <= MeleeRange)
                {
                    CastSpell(base.AbilityDictionary["先祖之锤"], D3Control.curTarget);
                }
                else
                {
                    var attackLocation = D3Control.getSideSpot(D3Control.Player.Location, D3Control.Player.Rotation, (int)MeleeRange);
                    CastSpell(base.AbilityDictionary["先祖之锤"], attackLocation);
                }
            }
        }
    }

    /// <summary>
    /// 野蛮人旋风流
    /// </summary>
    public class BarbarianWhirlwindCombatState : CombatStateBase
    {
        public BarbarianWhirlwindCombatState()
            : base()
        {
            CoreName = "野蛮人旋风流";
            CoreVersion = new Version(1, 0, 0);
        }

        /// <summary>
        /// 参数初始化
        /// </summary>
        protected override void PropertiesInit()
        {
            base.PropertiesInit();
        }

        /// <summary>
        /// 攻击重载
        /// </summary>
        protected override void Attack()
        {
            CheckBuff(base.AbilityDictionary["战吼"], true);
            CheckBuff(base.AbilityDictionary["战斗暴怒"]);
            CheckBuff(base.AbilityDictionary["冲刺"], false, 50, false, 0);
            if (IsTargetValid() && D3Control.curTarget.IsElite && (D3Control.curTarget.DistanceFromPlayer <= AoeRange || D3Control.curTarget.DistanceFromPlayer <= D3Control.getMobRange(D3Control.curTarget)))
            {
                CastSpell(base.AbilityDictionary["狂战之怒"], D3Control.Player);
            }
            if (IsTargetValid() && (D3Control.curTarget.DistanceFromPlayer <= 9 || D3Control.curTarget.DistanceFromPlayer <= D3Control.getMobRange(D3Control.curTarget)))
            {
                CastSpell(base.AbilityDictionary["霸气无双"]);
                CastSpell(base.AbilityDictionary["旋风斩"]);
            }
            if (IsTargetValid())
            {
                CastSpell(base.AbilityDictionary["顺劈斩"], 10, true);
            }
            base.Attack();
        }

        /// <summary>
        /// 拉怪重载
        /// </summary>
        /// <param name="target">目标</param>
        /// <returns></returns>
        protected override void DoPulling(D3Unit target)
        {
            base.DoPulling(target);
        }

        /// <summary>
        /// 范围攻击重载
        /// </summary>
        protected override void DoAoe()
        {
            CastSpell(base.AbilityDictionary["霸气无双"]);
            CastSpell(base.AbilityDictionary["旋风斩"]);
        }
    }

    #endregion

    #region Monk

    /// <summary>
    /// 武僧劲风流
    /// </summary>
    public class MonkSweepingWindCombatState : CombatStateBase
    {
        public MonkSweepingWindCombatState()
            : base()
        {
            base.CoreName = "武僧劲风流";
            base.CoreVersion = new Version(0, 2);
        }

        protected override void PropertiesInit()
        {
            base.PropertiesInit();
            base.MeleeRange = 20;
            base.AoeRange = 25;
            base.PetCount = 1;
        }

        protected override void SetAbilityDictionary()
        {
            base.SetAbilityDictionary();
        }

        protected override void SetHealthKeeperList()
        {
            base.SetHealthKeeperList();
            HealthKeeperList.Add(new HealthKeeper() { HpPct = 80, Ability = base.AbilityDictionary["回天气诀"], BaseResource = 10, IsBaseResource = true });
            HealthKeeperList.Add(new HealthKeeper() { HpPct = 50, Ability = base.AbilityDictionary["明镜止水"] });
            base.SortHealthKeeperList();
        }

        protected override void Attack()
        {
            CheckBuff(base.AbilityDictionary["定罪真言"]);
            CheckBuff(base.AbilityDictionary["回天气诀"]);
            CheckBuff(base.AbilityDictionary["劲风煞"]);
            CheckBuff(base.AbilityDictionary["天地元灵"]);

            if (IsTargetValid() && (D3Control.curTarget.DistanceFromPlayer <= AoeRange || D3Control.curTarget.DistanceFromPlayer <= D3Control.getMobRange(D3Control.curTarget)))
            {
                //CastSpell(base.AbilityDictionary["金钟破"], D3Control.curTarget, 25, true, 0);
                CastSpell(base.AbilityDictionary["奔雷拳"], D3Control.curTarget);
            }
            base.Attack();
        }

        /// <summary>
        /// 拉怪重载
        /// </summary>
        /// <param name="target">目标</param>
        /// <returns></returns>
        protected override void DoPulling(D3Unit target)
        {
            base.DoPulling(target);
        }

        /// <summary>
        /// 范围攻击重载
        /// </summary>
        protected override void DoAoe()
        {
            var attackLocation = D3Control.getSideSpot(D3Control.Player.Location, D3Control.Player.Rotation, (int)MeleeRange);
            CastSpell(base.AbilityDictionary["金钟破"], attackLocation);
            CheckBuff(base.AbilityDictionary["定罪真言"]);
            CheckBuff(base.AbilityDictionary["回天气诀"]);
            CheckBuff(base.AbilityDictionary["劲风煞"]);
        }
    }


    /// <summary>
    /// 武僧4殷娜劲风流
    /// </summary>
    public class MonkFourInnaCombatState : CombatStateBase
    {
        public MonkFourInnaCombatState()
            : base()
        {
            base.CoreName = "武僧4殷娜劲风流";
            base.CoreVersion = new Version(0, 2);
        }

        protected override void PropertiesInit()
        {
            base.PropertiesInit();
            base.MeleeRange = 20;
            base.AoeRange = 25;
        }

        protected override void SetAbilityDictionary()
        {
            base.SetAbilityDictionary();
            base.AbilityDictionary["劲风煞"].Cost = 5;
        }

        protected override void SetHealthKeeperList()
        {
            base.SetHealthKeeperList();
            HealthKeeperList.Add(new HealthKeeper() { HpPct = 80, Ability = base.AbilityDictionary["回天气诀"], BaseResource = 10, IsBaseResource = true });
            HealthKeeperList.Add(new HealthKeeper() { HpPct = 50, Ability = base.AbilityDictionary["明镜止水"] });
            base.SortHealthKeeperList();
        }

        protected override void Attack()
        {
            CheckBuff(base.AbilityDictionary["定罪真言"]);
            CheckBuff(base.AbilityDictionary["回天气诀"]);
            CheckBuff(base.AbilityDictionary["劲风煞"]);

            if (D3Control.Player.isBeingCCed())
            {
                CastSpell(base.AbilityDictionary["明镜止水"], D3Control.Player);
            }

            if (IsTargetValid() && (D3Control.curTarget.DistanceFromPlayer <= AoeRange || D3Control.curTarget.DistanceFromPlayer <= D3Control.getMobRange(D3Control.curTarget)))
            {
                CastSpell(base.AbilityDictionary["金钟破"], D3Control.curTarget, 25, true, 0);
                CastSpell(base.AbilityDictionary["奔雷拳"], D3Control.curTarget);
            }
            base.Attack();
        }

        /// <summary>
        /// 拉怪重载
        /// </summary>
        /// <param name="target">目标</param>
        /// <returns></returns>
        protected override void DoPulling(D3Unit target)
        {
            base.DoPulling(target);
        }

        /// <summary>
        /// 范围攻击重载
        /// </summary>
        protected override void DoAoe()
        {
            var attackLocation = D3Control.getSideSpot(D3Control.Player.Location, D3Control.Player.Rotation, (int)MeleeRange);
            CastSpell(base.AbilityDictionary["金钟破"], attackLocation);
            CheckBuff(base.AbilityDictionary["定罪真言"]);
            CheckBuff(base.AbilityDictionary["回天气诀"]);
            CheckBuff(base.AbilityDictionary["劲风煞"]);
        }
    }


    #endregion

    /// <summary>
    /// 战斗状态基类，可用于任何职业脚本，有实力的自己扩展
    /// Update Notes:
    /// ============
    /// 1.9.2
    /// ============
    /// 添加宠物判断
    /// 在技能特性是召唤宠物的情况下，在技能词典里加上属性：IsPetSpell = true
    /// 在protected override void PropertiesInit()里定义宠物数量：base.PetCount = 1;
    /// 然后可以使用CheckBuff(base.AbilityDictionary["天地元灵"]);来判断宠物
    /// ============
    /// 1.9.1
    /// ============
    /// 修正血线保护器的Bug
    /// 新增武僧普通劲风流，4Inna劲风流范例
    /// ============
    /// 1.9.0
    /// ============
    /// 添加血线保护器，使用方法看demo。
    /// ============
    /// 1.8.0
    /// ============
    /// 去除了阶梯范围选怪逻辑，该逻辑意义不大，对应的目标选择函数也做了相应的修改
    /// 极大的修复了卡怪的问题，默认日志开关开启，未知怪物会在日志中输出，对未知怪物会有特殊超时跳出循环的逻辑
    /// 去除了一些不使用的代码
    /// ============
    /// 1.7.2
    /// ============
    /// 添加重选目标开关，base.IsRetarget，使用方式见旋风流范例
    /// 修改CheckBuff函数，支持攻击类技能的Buff监视，支持CastSpell的复合参数，使用方式见旋风流的Attack
    /// ============
    /// 1.7.1
    /// ============
    /// 修复了蜘蛛女前乱跑以及类似情况下乱跑的Bug
    /// ============
    /// 1.7.0 beta
    /// ============
    /// 重构了技能词典函数，将职业的技能都放入了基类，子类就不需要再定义技能词典了
    /// 新增了技能实体的属性和对应的枚举，现在每个技能都有对应的施法类别了，记得自己扩展到技能词典函数里。
    /// 新增了锁定攻击目标词典和忽略攻击目标词典，可以将某些必须盯着抽到死的怪放入锁定列表，然后将那些骨堆，木堆什么的放入忽略攻击目标词典（注意某些忽略了可能会在战斗状态挡路，如果你不设置无目标的AOE技能）
    /// 优化了施法函数，现在统一使用CastSpell来施法，程序会根据每个法术的SpellType自动选择对应的施法类别。
    /// 重构了子类继承的结构，现在子类只需要很少量的代码就可以定制流派，具体的看Demo。
    /// 新增多级搜怪范围列表，基类自动根据由小到大排列这个顺序去阶梯搜怪
    /// 新增自定义怪物特性枚举，分为木桩型，被打就跑的远程型，同伴死亡后逃走型，会根据这个优先层级挨个打怪
    /// </summary>
    public abstract class CombatStateBase : Common.CombatState
    {
        /// <summary>
        /// 基类构造函数
        /// </summary>
        public CombatStateBase()
            : base()
        {
            BaseVersion = new Version(1, 9, 2);
        }

        #region 枚举

        /// <summary>
        /// 排序方式
        /// </summary>
        public enum SortType
        {
            /// <summary>
            /// 距离优先
            /// </summary>
            Distance,
            /// <summary>
            /// 怪物等级
            /// </summary>
            MLevel
        }

        /// <summary>
        /// 技能类型
        /// </summary>
        public enum SpellType
        {
            /// <summary>
            /// 地点类
            /// </summary>
            Location,
            /// <summary>
            /// 方向类
            /// </summary>
            Direction,
            /// <summary>
            /// 目标类
            /// </summary>
            Target,
        }

        /// <summary>
        /// 发呆类型
        /// </summary>
        public enum DazeType
        {
            /// <summary>
            /// 攻击目标的时候发呆
            /// </summary>
            Attack,
            /// <summary>
            /// 目标遍历的时候发呆
            /// </summary>
            Targets,
            /// <summary>
            /// 进入战斗后发呆
            /// </summary>
            Execute
        }

        /// <summary>
        /// 目标类型
        /// </summary>
        public enum TargetType
        {
            /// <summary>
            /// 打到死
            /// </summary>
            HitTillDie,
            /// <summary>
            /// 死了同伴就逃
            /// </summary>
            RunWhenOtherDie,
            /// <summary>
            /// 打了就跑
            /// </summary>
            HitAndRun,
            /// <summary>
            /// 特殊类型
            /// </summary>
            Special
        }

        #endregion

        #region 实体

        /// <summary>
        /// 技能实体
        /// </summary>
        public class Ability
        {
            /// <summary>
            /// 技能ID
            /// </summary>
            public string SpellID { get; set; }

            /// <summary>
            /// 花费
            /// </summary>
            public int Cost { get; set; }

            /// <summary>
            /// 是否是右键技能
            /// </summary>
            public bool isRightAbility { get; set; }

            /// <summary>
            /// 技能是否需要按住不放
            /// </summary>
            public bool IsHold { get; set; }

            /// <summary>
            /// 雕文名称
            /// </summary>
            public string RuneName { get; set; }

            /// <summary>
            /// 施法的技能类型
            /// </summary>
            public SpellType CastSpellType { get; set; }

            /// <summary>
            /// 是否是宠物技能
            /// </summary>
            public bool IsPetSpell { get; set; }
        }

        /// <summary>
        /// 自定义怪物信息实体
        /// </summary>
        public class CustomTarget
        {
            /// <summary>
            /// ID
            /// </summary>
            public int ID { get; set; }

            /// <summary>
            /// 名称
            /// </summary>
            public string Name { get; set; }

            /// <summary>
            /// 目标信息
            /// </summary>
            public D3Unit Target { get; set; }

            /// <summary>
            /// 怪物等级
            /// </summary>
            public int MLevel { get; set; }

            /// <summary>
            /// 对玩家的距离
            /// </summary>
            public float DistanceFromPlayer { get; set; }

            /// <summary>
            /// 攻击目标类型
            /// </summary>
            public TargetType AttackTargetType { get; set; }
        }

        /// <summary>
        /// 血线保护器
        /// </summary>
        public class HealthKeeper
        {
            /// <summary>
            /// 血线
            /// </summary>
            public int HpPct { get; set; }

            /// <summary>
            /// 技能
            /// </summary>
            public Ability Ability { get; set; }

            /// <summary>
            /// 是否是血球
            /// </summary>
            public bool IsHealthBall { get; set; }

            /// <summary>
            /// 是否是血瓶
            /// </summary>
            public bool IsPotion { get; set; }

            /// <summary>
            /// 基础保留资源
            /// </summary>
            public int BaseResource { get; set; }

            public bool IsBaseResource { get; set; }

            public int BaseResourcePlus { get; set; }
        }

        #endregion

        #region 属性和定义

        /// <summary>
        /// 脚本名称
        /// </summary>
        public string CoreName { get; set; }

        /// <summary>
        /// 脚本版本
        /// </summary>
        public Version CoreVersion { get; set; }

        /// <summary>
        /// 基类版本
        /// </summary>
        public Version BaseVersion { get; set; }

        /// <summary>
        /// 是否开启调试信息
        /// </summary>
        protected bool IsDebug { get; set; }

        /// <summary>
        /// 目标排序方式
        /// </summary>
        protected SortType TargetSortType { get; set; }

        /// <summary>
        /// 拾取距离
        /// </summary>
        protected float LootRange { get; set; }

        /// <summary>
        /// 技能列表
        /// </summary>
        protected Dictionary<string, Ability> AbilityDictionary { get; set; }

        /// <summary>
        /// 计时器词典
        /// </summary>
        protected Dictionary<string, CWSpellTimer> TimerDictionary { get; set; }

        /// <summary>
        /// 血线保护器列表
        /// </summary>
        protected List<HealthKeeper> HealthKeeperList { get; set; }

        /// <summary>
        /// 获取目标范围列表
        /// </summary>
        protected List<float> GetTargetsRangeList { get; set; }

        /// <summary>
        /// 近战距离
        /// </summary>
        protected float MeleeRange { get; set; }

        /// <summary>
        /// 范围攻击距离
        /// </summary>
        protected float AoeRange { get; set; }

        /// <summary>
        /// 寻找怪物距离
        /// </summary>
        protected float PatrolRange { get; set; }

        /// <summary>
        /// 最大距离
        /// </summary>
        protected float MaxRange { get; set; }

        /// <summary>
        /// 是否需要重选目标
        /// </summary>
        protected bool IsRetarget { get; set; }

        /// <summary>
        /// 释放技能间隔毫秒
        /// </summary>
        protected int SkillCastInterval { get; set; }

        /// <summary>
        /// 选择目标计时器间隔
        /// </summary>
        protected int ReTargetTimerInterval { get; set; }

        /// <summary>
        /// 发呆计时器检测间隔
        /// </summary>
        protected int DazeTimerInterval { get; set; }

        /// <summary>
        /// 未知目标计时器间隔
        /// </summary>
        protected int UnknownTargetTimerInterval { get; set; }

        /// <summary>
        /// 优先攻击目标词典
        /// </summary>
        protected List<CustomTarget> PriorityAttackTargets { get; set; }

        /// <summary>
        /// 延迟攻击目标词典
        /// </summary>
        protected List<CustomTarget> DelayAttackTargets { get; set; }

        /// <summary>
        /// 锁定攻击目标词典
        /// </summary>
        protected List<CustomTarget> LockAttackTargets { get; set; }

        /// <summary>
        /// 忽略攻击目标词典
        /// </summary>
        protected List<CustomTarget> IgnoreAttackTargets { get; set; }

        /// <summary>
        /// 宠物数量
        /// </summary>
        protected int PetCount { get; set; }

        /// <summary>
        /// 怪物词典
        /// </summary>
        private List<CustomTarget> MosterList { get; set; }

        /// <summary>
        /// 发呆计时器
        /// </summary>
        private CWSpellTimer DazeTimer { get; set; }

        /// <summary>
        /// 选择目标计时器
        /// </summary>
        private CWSpellTimer ReTargetTimer { get; set; }

        /// <summary>
        /// 未知目标计时器
        /// </summary>
        private CWSpellTimer UnknownTargetTimer { get; set; }

        /// <summary>
        /// 玩家坐标
        /// </summary>
        private Vector3D PlayerLocation { get; set; }

        /// <summary>
        /// 是否发呆中
        /// </summary>
        private bool IsDaze { get; set; }

        #endregion

        #region 初始化

        protected override void DoEnter(D3Player value)
        {
            base.DoEnter(value);
            PropertiesInit();
            SetAbilityDictionary();
            SetHealthKeeperList();
            SetMosterList();
            SetLockAttackTargets();
            SetPriorityAttackTargets();
            SetDelayAttackTargets();
            SetIgnoreAttackTargets();
        }

        /// <summary>
        /// 参数初始化
        /// </summary>
        protected virtual void PropertiesInit()
        {
            //是否启用调试
            IsDebug = true;
            //装备附带的拾取范围，用来精确控制吃血球
            LootRange = 7;
            //近战攻击距离
            MeleeRange = 5;
            //AOE技能攻击距离
            AoeRange = 17;
            //寻怪范围
            PatrolRange = 50;
            //技能成功释放后的间隔时间
            SkillCastInterval = 100;
            //防呆计时器间隔时间
            DazeTimerInterval = 10000;
            //重选目标计时器间隔时间
            ReTargetTimerInterval = 3500;
            //目标排序方式
            TargetSortType = SortType.Distance;
            //计时器初始化
            TimerDictionary = new Dictionary<string, CWSpellTimer>();
            //是否需要重选目标功能
            IsRetarget = true;
            //最大距离
            MaxRange = 200;
            //未知目标计时器间隔
            UnknownTargetTimerInterval = 5000;
        }

        /// <summary>
        /// 设置血线保护器列表
        /// </summary>
        protected virtual void SetHealthKeeperList()
        {
            if (HealthKeeperList == null)
            {
                HealthKeeperList = new List<HealthKeeper>();
            }

            HealthKeeperList.Add(new HealthKeeper() { HpPct = 70, IsHealthBall = true });
            HealthKeeperList.Add(new HealthKeeper() { HpPct = 40, IsPotion = true });

            SortHealthKeeperList();
        }

        /// <summary>
        /// 排序血线保护器列表
        /// </summary>
        protected void SortHealthKeeperList()
        {
            HealthKeeperList = HealthKeeperList.OrderBy(h => h.HpPct).ToList();
        }

        /// <summary>
        /// 设置技能词典
        /// </summary>
        protected virtual void SetAbilityDictionary()
        {
            if (AbilityDictionary == null)
            {
                AbilityDictionary = new Dictionary<string, Ability>();

                switch (D3Control.playerClass)
                {
                    case D3Control.ToonClass.Barbarian:

                        AbilityDictionary.Add("先祖之锤", new Ability() { SpellID = "Hammer of the Ancients", CastSpellType = SpellType.Direction, Cost = 20 });
                        AbilityDictionary.Add("开地猛击", new Ability() { SpellID = "Siesmic Slam", CastSpellType = SpellType.Direction, Cost = 30 });
                        AbilityDictionary.Add("撕裂", new Ability() { SpellID = "Rend", CastSpellType = SpellType.Direction, Cost = 20 });
                        AbilityDictionary.Add("战斗暴怒", new Ability() { SpellID = "Battle Rage", CastSpellType = SpellType.Direction, Cost = 20, RuneName = "Battle Rage" });
                        AbilityDictionary.Add("冲刺", new Ability() { SpellID = "Sprint", CastSpellType = SpellType.Direction, Cost = 20, RuneName = "Sprint" });
                        AbilityDictionary.Add("旋风斩", new Ability() { SpellID = "Whirlwind", IsHold = true, CastSpellType = SpellType.Direction, Cost = 10 });
                        AbilityDictionary.Add("裂地之震", new Ability() { SpellID = "Earthquakes", CastSpellType = SpellType.Direction, Cost = 50 });
                        AbilityDictionary.Add("上古召唤", new Ability() { SpellID = "Call of the Ancients", CastSpellType = SpellType.Direction, Cost = 50 });
                        AbilityDictionary.Add("狂战之怒", new Ability() { SpellID = "Wrath of the Berserker", CastSpellType = SpellType.Direction, Cost = 50 });
                        AbilityDictionary.Add("震地践踏", new Ability() { SpellID = "Ground Stomp", CastSpellType = SpellType.Direction });
                        AbilityDictionary.Add("复仇", new Ability() { SpellID = "Revenge", CastSpellType = SpellType.Direction });
                        AbilityDictionary.Add("霸气无双", new Ability() { SpellID = "Overpower", CastSpellType = SpellType.Direction });
                        AbilityDictionary.Add("战吼", new Ability() { SpellID = "War Cry", CastSpellType = SpellType.Direction, RuneName = "War Cry" });
                        AbilityDictionary.Add("威慑怒吼", new Ability() { SpellID = "Threatening Shout", CastSpellType = SpellType.Direction });

                        AbilityDictionary.Add("掷刃斩", new Ability() { SpellID = "Weapon Throw", Cost = 10, CastSpellType = SpellType.Location });
                        AbilityDictionary.Add("Furious Charge", new Ability() { SpellID = "Furious Charge", CastSpellType = SpellType.Location });
                        AbilityDictionary.Add("跃击", new Ability() { SpellID = "LeapAttack", CastSpellType = SpellType.Location });
                        AbilityDictionary.Add("上古之矛", new Ability() { SpellID = "Ancient Spear", CastSpellType = SpellType.Location });

                        AbilityDictionary.Add("猛击", new Ability() { SpellID = "Bash", CastSpellType = SpellType.Target });
                        AbilityDictionary.Add("顺劈斩", new Ability() { SpellID = "Cleave", CastSpellType = SpellType.Target });
                        AbilityDictionary.Add("狂乱", new Ability() { SpellID = "Frenzy", CastSpellType = SpellType.Target });

                        break;

                    case D3Control.ToonClass.DemonHunter:

                        //TODO

                        break;

                    case D3Control.ToonClass.Monk:

                        AbilityDictionary.Add("云龙摆尾", new Ability() { SpellID = "Lashing Tail Kick", CastSpellType = SpellType.Direction, Cost = 30 });
                        AbilityDictionary.Add("炫目神光", new Ability() { SpellID = "Blinding Flash", CastSpellType = SpellType.Direction, Cost = 10 });
                        AbilityDictionary.Add("回天气诀", new Ability() { SpellID = "Breath of Heaven", CastSpellType = SpellType.Direction, Cost = 25, RuneName = "Blazing Wrath" });
                        AbilityDictionary.Add("明镜止水", new Ability() { SpellID = "Serenity", CastSpellType = SpellType.Direction, Cost = 10 });
                        AbilityDictionary.Add("八相阵", new Ability() { SpellID = "Inner Sanctuary", CastSpellType = SpellType.Direction, Cost = 30 });
                        AbilityDictionary.Add("劲风煞", new Ability() { SpellID = "Sweeping Wind", CastSpellType = SpellType.Direction, Cost = 75, RuneName = "Sweeping Wind" });
                        AbilityDictionary.Add("旋风转", new Ability() { SpellID = "Cyclone Strike", CastSpellType = SpellType.Direction, Cost = 50 });
                        AbilityDictionary.Add("天地元灵", new Ability() { SpellID = "Mystic Ally", CastSpellType = SpellType.Direction, Cost = 25, IsPetSpell = true });
                        AbilityDictionary.Add("闪避真言", new Ability() { SpellID = "Mantra of Evasion", CastSpellType = SpellType.Direction, Cost = 50, RuneName = "Mantra of Evasion" });
                        AbilityDictionary.Add("惩戒真言", new Ability() { SpellID = "Mantra of Retribution", CastSpellType = SpellType.Direction, Cost = 50, RuneName = "Mantra of Retribution" });
                        AbilityDictionary.Add("治疗真言", new Ability() { SpellID = "Mantra of Healing", CastSpellType = SpellType.Direction, Cost = 50, RuneName = "Mantra of Healing" });
                        AbilityDictionary.Add("定罪真言", new Ability() { SpellID = "Mantra of Conviction", CastSpellType = SpellType.Direction, Cost = 50, RuneName = "Mantra of Conviction" });
                        AbilityDictionary.Add("金钟破", new Ability() { SpellID = "Wave of Light", CastSpellType = SpellType.Direction, Cost = 75 });
                        AbilityDictionary.Add("七星闪", new Ability() { SpellID = "Seven-Sided Strike", CastSpellType = SpellType.Direction, Cost = 50 });
                        AbilityDictionary.Add("爆裂掌", new Ability() { SpellID = "Exploding Palm", CastSpellType = SpellType.Direction, Cost = 40 });

                        AbilityDictionary.Add("暴风奔袭", new Ability() { SpellID = "Tempest Rush", CastSpellType = SpellType.Location, Cost = 15 });
                        AbilityDictionary.Add("瞬影打", new Ability() { SpellID = "Dashing Strike", CastSpellType = SpellType.Location, Cost = 25 });

                        AbilityDictionary.Add("奔雷拳", new Ability() { SpellID = "Fists of Thunder", CastSpellType = SpellType.Target });
                        AbilityDictionary.Add("断空波", new Ability() { SpellID = "Deadly Reach", CastSpellType = SpellType.Target });
                        AbilityDictionary.Add("伏魔破", new Ability() { SpellID = "Crippling Wave", CastSpellType = SpellType.Target });
                        AbilityDictionary.Add("百烈拳", new Ability() { SpellID = "Way of the Hundred Fists", CastSpellType = SpellType.Target });

                        break;

                    case D3Control.ToonClass.WitchDoctor:

                        //TODO

                        break;

                    case D3Control.ToonClass.Wizard:

                        //TODO

                        break;
                }
            }
        }

        /// <summary>
        /// 设置怪物词典
        /// </summary>
        private void SetMosterList()
        {
            if (MosterList == null)
            {
                MosterList = new List<CustomTarget>();

                #region 打到死
                var hitTillDieList = new List<CustomTarget>();

                hitTillDieList.Add(new CustomTarget() { ID = 4095, Name = "沉沦魔炸弹狂" });
                hitTillDieList.Add(new CustomTarget() { ID = 144315, Name = "烈火食尸鬼" });
                hitTillDieList.Add(new CustomTarget() { ID = 5581, Name = "勾勒巨魔" });
                hitTillDieList.Add(new CustomTarget() { ID = 203048, Name = "钻岩虫" });
                hitTillDieList.Add(new CustomTarget() { ID = 4092, Name = "沉沦魔地狱犬" });
                hitTillDieList.Add(new CustomTarget() { ID = 141194, Name = "恶魔劫掠者" });
                hitTillDieList.Add(new CustomTarget() { ID = 230725, Name = "地狱攻城兽" });
                hitTillDieList.Add(new CustomTarget() { ID = 4295, Name = "血族战士" });
                hitTillDieList.Add(new CustomTarget() { ID = 204979, Name = "血族战士2" });
                hitTillDieList.Add(new CustomTarget() { ID = 4296, Name = "血族打击兵" });
                hitTillDieList.Add(new CustomTarget() { ID = 171283, Name = "地狱哨卫" });
                hitTillDieList.Add(new CustomTarget() { ID = 120652, Name = "地狱哨卫2" });
                hitTillDieList.Add(new CustomTarget() { ID = 4738, Name = "瘟疫使者" });
                hitTillDieList.Add(new CustomTarget() { ID = 60722, Name = "地震魔" });
                hitTillDieList.Add(new CustomTarget() { ID = 205767, Name = "狱甲地震魔" });
                hitTillDieList.Add(new CustomTarget() { ID = 121353, Name = "凶暴移形兽" });
                hitTillDieList.Add(new CustomTarget() { ID = 4746, Name = "冥河毒蝎2" });
                hitTillDieList.Add(new CustomTarget() { ID = 4747, Name = "冥河毒蝎" });
                hitTillDieList.Add(new CustomTarget() { ID = 169615, Name = "苔魂兽" });
                hitTillDieList.Add(new CustomTarget() { ID = 4073, Name = "沉沦魔奴隶主" });
                hitTillDieList.Add(new CustomTarget() { ID = 220377, Name = "沉沦魔奴隶主[紫]" });
                hitTillDieList.Add(new CustomTarget() { ID = 137139, Name = "蜘蛛女王小虫" });
                hitTillDieList.Add(new CustomTarget() { ID = 192850, Name = "浮肿的马勒寇魔" });

                hitTillDieList.Add(new CustomTarget() { ID = 189852, Name = "未知189852" });
                hitTillDieList.Add(new CustomTarget() { ID = 220850, Name = "未知220850" });
                hitTillDieList.Add(new CustomTarget() { ID = 132951, Name = "未知132951" });
                
                hitTillDieList.ForEach(t => { t.AttackTargetType = TargetType.HitTillDie; });

               

                #endregion

                #region 死了同伴就跑

                var runWhenOtherDieList = new List<CustomTarget>();

                runWhenOtherDieList.Add(new CustomTarget() { ID = 4084, Name = "沉沦魔士兵[喽啰]" });
                runWhenOtherDieList.Add(new CustomTarget() { ID = 4085, Name = "沉沦魔士兵" });

                runWhenOtherDieList.ForEach(t => { t.AttackTargetType = TargetType.RunWhenOtherDie; });

                #endregion

                #region 打了就跑

                var hitAndRunList = new List<CustomTarget>();

                hitAndRunList.Add(new CustomTarget() { ID = 95250, Name = "蜘蛛女王" });
                hitAndRunList.Add(new CustomTarget() { ID = 4303, Name = "血族法师" });
                hitAndRunList.Add(new CustomTarget() { ID = 4304, Name = "血族玄术师" });
                hitAndRunList.Add(new CustomTarget() { ID = 130794, Name = "魔克拉妖蝠" });
                hitAndRunList.Add(new CustomTarget() { ID = 365, Name = "沉沦魔火法师" });
                hitAndRunList.Add(new CustomTarget() { ID = 4299, Name = "血族矛兵" });
                hitAndRunList.Add(new CustomTarget() { ID = 204981, Name = "血族矛兵2" });
                hitAndRunList.Add(new CustomTarget() { ID = 4300, Name = "血族标枪兵" });
                hitAndRunList.Add(new CustomTarget() { ID = 5508, Name = "魅魔" });                
                hitAndRunList.Add(new CustomTarget() { ID = 5985, Name = "哥布林1" });
                hitAndRunList.Add(new CustomTarget() { ID = 5986, Name = "哥布林2" });
                hitAndRunList.Add(new CustomTarget() { ID = 5987, Name = "哥布林3" });

                hitAndRunList.Add(new CustomTarget() { ID = 5984, Name = "未知5984" });
                hitAndRunList.Add(new CustomTarget() { ID = 5988, Name = "未知5988" });

                
                hitAndRunList.ForEach(t => { t.AttackTargetType = TargetType.HitAndRun; });
                #endregion

                #region 特殊类型

                var specialList = new List<CustomTarget>();

                specialList.Add(new CustomTarget() { ID = 193077, Name = "罪恶之心" });

                specialList.ForEach(t => { t.AttackTargetType = TargetType.Special; });

                #endregion

                MosterList.AddRange(hitTillDieList);
                MosterList.AddRange(runWhenOtherDieList);
                MosterList.AddRange(hitAndRunList);
                MosterList.AddRange(specialList);
            }
        }

        /// <summary>
        /// 设置锁定攻击目标
        /// </summary>
        protected virtual void SetLockAttackTargets()
        {
            if (LockAttackTargets == null)
            {
                LockAttackTargets = new List<CustomTarget>();
                LockAttackTargets.Add(new CustomTarget() { ID = 95250, Name = "蜘蛛女王" });
            }
        }

        /// <summary>
        /// 设置优先攻击目标
        /// </summary>
        protected virtual void SetPriorityAttackTargets()
        {
            if (PriorityAttackTargets == null)
            {
                PriorityAttackTargets = new List<CustomTarget>();
                PriorityAttackTargets.Add(new CustomTarget() { ID = 4095, Name = "沉沦魔炸弹狂" });
                PriorityAttackTargets.Add(new CustomTarget() { ID = 5508, Name = "魅魔" });
                PriorityAttackTargets.Add(new CustomTarget() { ID = 5508, Name = "沉沦魔火法师" });
                PriorityAttackTargets.Add(new CustomTarget() { ID = 4303, Name = "血族法师" });
                PriorityAttackTargets.Add(new CustomTarget() { ID = 4304, Name = "血族玄术师" });
            }
        }

        /// <summary>
        /// 设置延迟攻击目标
        /// </summary>
        protected virtual void SetDelayAttackTargets()
        {
            if (DelayAttackTargets == null)
            {
                DelayAttackTargets = new List<CustomTarget>();
                DelayAttackTargets.Add(new CustomTarget() { ID = 144315, Name = "烈火食尸鬼" });
                DelayAttackTargets.Add(new CustomTarget() { ID = 203048, Name = "钻岩虫" });
                DelayAttackTargets.Add(new CustomTarget() { ID = 193077, Name = "罪恶之心" });
            }
        }

        /// <summary>
        /// 设置忽略攻击目标
        /// </summary>
        protected virtual void SetIgnoreAttackTargets()
        {
            if (IgnoreAttackTargets == null)
            {
                IgnoreAttackTargets = new List<CustomTarget>();
                IgnoreAttackTargets.Add(new CustomTarget() { ID = 185391, Name = "喷火龙头" });
                IgnoreAttackTargets.Add(new CustomTarget() { ID = 174900, Name = "喷火龙头2" });
            }
        }

        #endregion

        #region 释放技能

        /// <summary>
        /// 释放技能
        /// </summary>
        /// <param name="ability"></param>
        /// <param name="baseResource"></param>
        /// <param name="isBaseResource"></param>
        /// <param name="baseResourcePlus"></param>
        /// <returns></returns>
        protected bool CastSpell(Ability ability, int baseResource = 0, bool isBaseResource = false, int baseResourcePlus = 0)
        {
            var castResult = false;
            switch (ability.CastSpellType)
            {
                case SpellType.Direction:
                    castResult = CastDirectionSpell(ability, D3Control.curTarget.Location, baseResource, isBaseResource, baseResourcePlus);
                    break;
                case SpellType.Target:
                    castResult = CastTargetSpell(ability, D3Control.curTarget, baseResource, isBaseResource, baseResourcePlus);
                    break;
                case SpellType.Location:
                    castResult = CastLocationSpell(ability, D3Control.Player.Location, baseResource, isBaseResource, baseResourcePlus);
                    break;
            }
            return castResult;
        }

        /// <summary>
        /// 释放技能
        /// </summary>
        /// <param name="ability"></param>
        /// <param name="baseResource"></param>
        /// <param name="isBaseResource"></param>
        /// <param name="baseResourcePlus"></param>
        /// <returns></returns>
        protected bool CastSpell(Ability ability, D3Object d3Object, int baseResource = 0, bool isBaseResource = false, int baseResourcePlus = 0)
        {
            var castResult = false;
            switch (ability.CastSpellType)
            {
                case SpellType.Direction:
                    castResult = CastDirectionSpell(ability, d3Object.Location, baseResource, isBaseResource, baseResourcePlus);
                    break;
                case SpellType.Target:
                    castResult = CastTargetSpell(ability, d3Object, baseResource, isBaseResource, baseResourcePlus);
                    break;
                case SpellType.Location:
                    castResult = CastLocationSpell(ability, d3Object.Location, baseResource, isBaseResource, baseResourcePlus);
                    break;
            }
            return castResult;
        }

        /// <summary>
        /// 释放技能
        /// </summary>
        /// <param name="ability"></param>
        /// <param name="baseResource"></param>
        /// <param name="isBaseResource"></param>
        /// <param name="baseResourcePlus"></param>
        /// <returns></returns>
        protected bool CastSpell(Ability ability, Vector3D location, int baseResource = 0, bool isBaseResource = false, int baseResourcePlus = 0)
        {
            var castResult = false;
            switch (ability.CastSpellType)
            {
                case SpellType.Direction:
                    castResult = CastDirectionSpell(ability, location, baseResource, isBaseResource, baseResourcePlus);
                    break;
                case SpellType.Location:
                    castResult = CastLocationSpell(ability, location, baseResource, isBaseResource, baseResourcePlus);
                    break;
            }
            return castResult;
        }

        /// <summary>
        /// 释放目标类技能
        /// </summary>
        /// <param name="ability">技能实体</param>
        /// <param name="baseResource">保留基本资源值</param>
        /// <param name="isBaseResource">是否保留基本资源值</param>
        /// <param name="baseResourcePlus">附加资源值</param>
        /// <returns></returns>
        private bool CastTargetSpell(Ability ability, D3Object target, int baseResource = 0, bool isBaseResource = false, int baseResourcePlus = 0)
        {
            baseResource = isBaseResource ? (baseResource + baseResourcePlus) : baseResource;
            if (isBaseResource)
            {
                if (GetPlayerResource(D3Control.playerClass) <= baseResource)
                {
                    var result = D3Control.CastTargetSpell(ability.SpellID, target);
                    if (result)
                    {
                        Thread.Sleep(SkillCastInterval);
                    }
                    return result;
                }
                return false;
            }
            else
            {
                return D3Control.CastTargetSpell(ability.SpellID, target);
            }
        }

        /// <summary>
        /// 释放方向类技能
        /// </summary>
        /// <param name="ability">技能实体</param>
        /// <param name="loc">坐标</param>
        /// <param name="baseResource">保留基本资源值</param>
        /// <param name="isBaseResource">是否保留基本资源值</param>
        /// <param name="baseResourcePlus">附加资源值</param>
        /// <returns></returns>
        private bool CastDirectionSpell(Ability ability, Vector3D loc, int baseResource = 0, bool isBaseResource = false, int baseResourcePlus = 0)
        {
            baseResource = isBaseResource ? (baseResource + baseResourcePlus) : baseResource;
            var result = IsEnoughResourceForSpell(ability, baseResource) ? (D3Control.CastDirectionSpell(ability.SpellID, loc)) : false;
            if (result)
            {
                Thread.Sleep(SkillCastInterval);
            }
            return result;
        }

        /// <summary>
        /// 释放位置类技能
        /// </summary>
        /// <param name="ability">技能实体</param>
        /// <param name="loc">坐标</param>
        /// <param name="baseResource">保留基本资源值</param>
        /// <param name="isBaseResource">是否保留基本资源值</param>
        /// <param name="baseResourcePlus">附加资源值</param>
        /// <returns></returns>
        private bool CastLocationSpell(Ability ability, Vector3D loc, int baseResource = 0, bool isBaseResource = false, int baseResourcePlus = 0)
        {
            baseResource = isBaseResource ? (baseResource + baseResourcePlus) : baseResource;
            var result = IsEnoughResourceForSpell(ability, baseResource) ? (D3Control.CastLocationSpell(ability.SpellID, loc, ability.IsHold)) : false;
            if (result)
            {
                Thread.Sleep(SkillCastInterval);
            }
            return result;
        }

        /// <summary>
        /// 技能是否可以释放
        /// </summary>
        /// <param name="ability"></param>
        /// <returns></returns>
        protected bool CanCast(Ability ability)
        {
            return D3Control.canCast(ability.SpellID);
        }

        /// <summary>
        /// 判断是否有足够的资源释放技能
        /// </summary>
        /// <param name="ability">技能实体</param>
        /// <param name="baseResource">保留基本资源值</param>
        /// <returns></returns>
        private bool IsEnoughResourceForSpell(Ability ability, int baseResource)
        {
            var resource = GetPlayerResource(D3Control.playerClass, ability.isRightAbility);
            return (CanCast(ability) && resource >= (ability.Cost + baseResource));
        }

        #endregion

        #region 目标相关

        /// <summary>
        /// 目标是否有效
        /// </summary>
        /// <returns></returns>
        protected bool IsTargetValid()
        {
            if (D3Control.isObjectValid(D3Control.curTarget))
            {
                if (D3Control.curTarget.IsDead || D3Control.curTarget.MaxHp <= 1 || D3Control.curTarget.Hp <= 1)
                {
                    return false;
                }
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 根据范围列表获取攻击目标
        /// 注意范围列表的最小值和最大值分别不要比MeleeRange小和PatrolRange大
        /// </summary>
        /// <returns></returns>
        protected List<D3Unit> GetAttackTargetsByRangeList()
        {
            var sortedTargets = new List<D3Unit>();
            var targets = D3Control.TargetManager.GetAroundEnemy(PatrolRange);

            targets.RemoveAll(t =>
            {
                return !D3Control.isObjectValid(t) || t.Hp <= 1 || t.MaxHp <= 1 || t.DistanceFromPlayer > MaxRange;
            });

            if (targets.Count > 0)
            {
                var delayAttackTargets = GetSpecialAttackTargets(targets, DelayAttackTargets);
                delayAttackTargets.ForEach(t => { targets.Remove(t); });

                var ignoreAttackTargets = GetSpecialAttackTargets(targets, IgnoreAttackTargets);
                ignoreAttackTargets.ForEach(t => { targets.Remove(t); });

                sortedTargets.AddRange(GetAttackTargets(targets));
                sortedTargets.AddRange(delayAttackTargets);
            }

            return sortedTargets;
        }

        /// <summary>
        /// 获取攻击目标列表
        /// </summary>
        /// <param name="targets">目标列表</param>
        /// <returns></returns>
        protected List<D3Unit> GetAttackTargets(List<D3Unit> targets)
        {
            var sortedTargets = new List<D3Unit>();

            if (targets.Count > 0)
            {
                var priorityAttackTargets = GetSpecialAttackTargets(targets, PriorityAttackTargets);
                priorityAttackTargets.ForEach(t => { targets.Remove(t); });

                var lockAttackTargets = GetSpecialAttackTargets(targets, LockAttackTargets);
                lockAttackTargets.ForEach(t => { targets.Remove(t); });

                sortedTargets.AddRange(SortTargets(lockAttackTargets));
                sortedTargets.AddRange(SortTargets(priorityAttackTargets));
                sortedTargets.AddRange(SortTargets(targets));
            }
            return sortedTargets;
        }

        /// <summary>
        /// 排序目标列表
        /// </summary>
        /// <param name="targets"></param>
        /// <returns></returns>
        private List<D3Unit> SortTargets(List<D3Unit> targets)
        {
            var runWhenOtherDieTargets = new List<D3Unit>();
            var hitAndRunTargets = new List<D3Unit>();

            var runWhenOtherDieList = MosterList.FindAll(t => t.AttackTargetType == TargetType.RunWhenOtherDie);
            var hitAndRunList = MosterList.FindAll(t => t.AttackTargetType == TargetType.HitAndRun);

            targets.ForEach(t =>
            {
                if (runWhenOtherDieList.Exists(c => c.ID == t.ID))
                {
                    runWhenOtherDieTargets.Add(t);
                }
                if (hitAndRunList.Exists(c => c.ID == t.ID))
                {
                    hitAndRunTargets.Add(t);
                }
            });

            runWhenOtherDieTargets.ForEach(t => { targets.Remove(t); });
            hitAndRunTargets.ForEach(t => { targets.Remove(t); });

            var targetsListParts = new List<List<D3Unit>>() { targets, runWhenOtherDieTargets, hitAndRunTargets };

            var sortedList = new List<D3Unit>();

            targetsListParts.ForEach(p =>
            {
                switch (TargetSortType)
                {
                    case SortType.Distance:
                        p = p.OrderByDescending(t => t.MLevel).OrderBy(t => t.DistanceFromPlayer).ToList();
                        break;
                    case SortType.MLevel:
                        p = p.OrderBy(t => t.DistanceFromPlayer).OrderByDescending(t => t.MLevel).ToList();
                        break;
                    default:
                        p = p.OrderByDescending(t => t.MLevel).OrderBy(t => t.DistanceFromPlayer).ToList();
                        break;
                }

                p.ForEach(t =>
                {
                    sortedList.Add(t);
                });
            });
            return sortedList;
        }

        /// <summary>
        /// 获取特殊攻击目标列表
        /// </summary>
        /// <param name="targets"></param>
        /// <param name="specialTargets"></param>
        /// <returns></returns>
        private List<D3Unit> GetSpecialAttackTargets(List<D3Unit> targets, List<CustomTarget> specialTargets)
        {
            var specialTargetList = new List<D3Unit>();
            targets.ForEach(t =>
            {
                if (specialTargets.Exists(p => p.ID == t.ID))
                {
                    specialTargetList.Add(t);
                }
            });
            return specialTargetList;
        }

        #endregion

        #region 战斗中属性检查

        /// <summary>
        /// 检查Buff
        /// </summary>
        /// <param name="ability">技能实体</param>
        /// <param name="isUseIfCanCast">如果能释放了是否立即使用</param>
        /// <returns></returns>
        protected bool CheckBuff(Ability ability, bool isUseIfCanCast = false, int baseResource = 0, bool isBaseResource = false, int baseResourcePlus = 0)
        {
            if (ability.IsPetSpell)
            {
                if (D3Control.GetPetCount(0) != PetCount)
                {
                    return CastSpell(ability, D3Control.Player, baseResource, isBaseResource, baseResourcePlus);
                }
            }
            else
            {
                if (isUseIfCanCast)
                {
                    CastSpell(ability, D3Control.Player, baseResource, isBaseResource, baseResourcePlus);
                }
                else
                {
                    if (!D3Control.HasBuff(ability.RuneName))
                    {
                        return CastSpell(ability, D3Control.Player, baseResource, isBaseResource, baseResourcePlus);
                    }
                }
            }
            return true;
        }

        /// <summary>
        /// 检查玩家血量百分比
        /// </summary>
        protected virtual void CheckPlayerHpPct()
        {
            var playerHpPct = GetPlayerHpPct();

            HealthKeeperList.ForEach(h =>
            {
                if (playerHpPct < h.HpPct)
                {
                    if (h.IsHealthBall)
                    {
                        var healthGlobe = D3Control.ClosestHealthGlobe;
                        if (healthGlobe != null && !DistanceCompare(D3Control.Player, healthGlobe, LootRange + 10f))
                        {
                            D3Control.MoveTo(healthGlobe, 10f);
                        }
                    }
                    else if (h.IsPotion)
                    {
                        D3Control.usePotion();
                    }
                    else
                    {
                        CastSpell(h.Ability, h.BaseResource, h.IsBaseResource, h.BaseResourcePlus);
                    }
                }

                playerHpPct = GetPlayerHpPct();
            });
        }

        /// <summary>
        /// 获取玩家血量
        /// </summary>
        /// <returns></returns>
        private int GetPlayerHpPct()
        {
            var playerHpPct = D3Control.Player.HpPct;
            if (playerHpPct <= -100 || playerHpPct >= 100)
            {
                playerHpPct = 100;
            }
            return playerHpPct;
        }

        #endregion

        #region 战斗相关

        /// <summary>
        /// 随机移动
        /// </summary>
        /// <returns></returns>
        private bool MoveRandom()
        {
            var randomX = new Random(DateTime.Now.Millisecond);
            var x = randomX.Next(-10, 10);
            Thread.Sleep(50);
            var randomY = new Random(DateTime.Now.Millisecond);
            var y = randomY.Next(-10, 10);
            Thread.Sleep(50);
            var tmpLocation = D3Control.Player.Location.CloneVector();
            tmpLocation.X += x;
            tmpLocation.Y += y;
            if (!D3Control.LOS(tmpLocation))
            {
                D3Control.ClickMoveTo(tmpLocation);
                return true;
            }
            return false;
        }

        /// <summary>
        /// 移动到战斗地点
        /// </summary>
        protected virtual bool MoveToStartFight()
        {
            if (D3Control.getDoorInWay(D3Control.curTarget) != null)
            {
                D3Control.MoveTo(D3Control.curTarget, 2.5f);
            }
            if (IsTargetValid())
            {
                if (D3Control.curTarget.DistanceFromPlayer > AoeRange || D3Control.LOS(D3Control.curTarget.Location))
                {
                    var playerLocation = D3Control.Player.Location.CloneVector();
                    D3Control.MoveTo(D3Control.curTarget, MeleeRange);
                    Thread.Sleep(300);
                    if (D3Control.Player.Location.GetDistanceTo(playerLocation) < 1)
                    {
                        DoAoe();
                    }
                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// 攻击
        /// </summary>
        protected virtual void Attack()
        {
            //当前目标是锁定目标，打到死或者没法选中为止
            if (IsTargetValid() && LockAttackTargets.Exists(t => t.ID == D3Control.curTarget.ID))
            {
                if (IsRetarget)
                {
                    ReTargetTimer.Reset();
                }
                DazeTimer.Reset();
            }
        }

        /// <summary>
        /// 范围攻击
        /// </summary>
        protected virtual void DoAoe() { }

        /// <summary>
        /// 拉怪
        /// </summary>
        /// <param name="target"></param>
        protected virtual void DoPulling(D3Unit target)
        {
            D3Control.TargetManager.ClearTarget();
            D3Control.TargetManager.SetAttackTarget(target);

            if (!IsTargetValid())
            {
                return;
            }

            var isUnknownTarget = false;

            if (!MosterList.Exists(t => t.ID == D3Control.curTarget.ID))
            {
                Output(string.Format("[未知怪物信息]\r\nID：{0}\r\n血量：{1}\r\n最大血量：{2}\r\n距离：{3}", D3Control.curTarget.ID, D3Control.curTarget.Hp, D3Control.curTarget.MaxHp, D3Control.curTarget.DistanceFromPlayer));
                UnknownTargetTimer = new CWSpellTimer(UnknownTargetTimerInterval, false);
                isUnknownTarget = true;
            }

            while (D3Control.IsInGame() && !D3Control.Player.IsDead)
            {
                if (DazeTimer.IsReady)
                {
                    if (IsDaze)
                    {
                        break;
                    }
                    CheckDazeTimer(DazeType.Attack);
                    if (IsDaze)
                    {
                        break;
                    }
                }
                if (MoveToStartFight())
                {
                    if (!IsTargetValid())
                    {
                        break;
                    }
                    Attack();
                }
                else
                {
                    break;
                }

                CheckPlayerHpPct();

                if (IsRetarget && ReTargetTimer.IsReady)
                {
                    break;
                }

                if (isUnknownTarget && UnknownTargetTimer.IsReady)
                {
                    break;
                }
            }

            D3Control.checkLoots();
            CheckPlayerHpPct();
        }

        /// <summary>
        /// 重载基类战斗函数
        /// </summary>
        /// </summary>
        protected override void DoExecute(D3Player Entity)
        {
            if (!GlobalBaseBotState.checkBeforePull(Entity))
            {
                return;
            }

            StartDazeTimer();
            ReTargetTimer = new CWSpellTimer(ReTargetTimerInterval, false);

            while (D3Control.IsInGame() && !D3Control.Player.IsDead)
            {
                if (DazeTimer.IsReady)
                {
                    if (IsDaze)
                    {
                        break;
                    }
                    CheckDazeTimer(DazeType.Attack);
                    if (IsDaze)
                    {
                        break;
                    }
                }

                D3Control.updateDungoneInfo();

                D3Control.checkLoots();
                CheckPlayerHpPct();

                var targets = GetAttackTargetsByRangeList();
                if (targets.Count > 0)
                {
                    targets.ForEach(t =>
                    {
                        if (IsRetarget)
                        {
                            ReTargetTimer.Reset();
                        }
                        DoPulling(t);
                        if (IsRetarget && ReTargetTimer.IsReady)
                        {
                            return;
                        }
                        if (DazeTimer.IsReady)
                        {
                            if (IsDaze)
                            {
                                return;
                            }
                            CheckDazeTimer(DazeType.Attack);
                            if (IsDaze)
                            {
                                return;
                            }
                        }
                    });

                    if (IsRetarget)
                    {
                        continue;
                    }
                }
                else
                {
                    while (true)
                    {
                        if (MoveRandom())
                        {
                            break;
                        }
                    }
                    DoAoe();
                    break;
                }
            }
        }

        #endregion

        #region 发呆检测

        /// <summary>
        /// 启动发呆检测
        /// </summary>
        private void StartDazeTimer()
        {
            IsDaze = false;
            PlayerLocation = D3Control.Player.Location.CloneVector();
            DazeTimer = new CWSpellTimer(DazeTimerInterval, false);
        }

        /// <summary>
        /// 检查发呆
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CheckDazeTimer(DazeType dazeType)
        {
            var currentPlayerLocation = D3Control.Player.Location.CloneVector();
            var distance = currentPlayerLocation.GetDistanceTo(PlayerLocation);
            if (distance < 5)
            {
                switch (dazeType)
                {
                    case DazeType.Attack:
                        Output("检测到攻击目标的时候发呆，尝试离开战斗状态");
                        break;
                    case DazeType.Targets:
                        Output("检测到遍历目标的时候发呆，尝试离开战斗状态");
                        break;
                    case DazeType.Execute:
                        Output("检测到进入战斗时候发呆，尝试离开战斗状态");
                        break;
                }

                IsDaze = true;
            }
        }

        #endregion

        #region 其他

        /// <summary>
        /// 获取玩家资源值
        /// </summary>
        /// <param name="playerClass"></param>
        /// <returns></returns>
        protected int GetPlayerResource(D3Control.ToonClass playerClass, bool isRightResource = false)
        {
            int resource = 0;
            switch (D3Control.playerClass)
            {
                case D3Control.ToonClass.Barbarian:
                    resource = (int)D3Control.Player.Fury;
                    break;
                case D3Control.ToonClass.DemonHunter:
                    resource = isRightResource ? (int)D3Control.Player.Disc : (int)D3Control.Player.Hatred;
                    break;
                case D3Control.ToonClass.Monk:
                    resource = (int)D3Control.Player.Spirit;
                    break;
                case D3Control.ToonClass.WitchDoctor:
                    resource = (int)D3Control.Player.Mp;
                    break;
                case D3Control.ToonClass.Wizard:
                    resource = isRightResource ? (int)D3Control.Player.Mp : (int)D3Control.Player.ArcanePower;
                    break;
            }
            return resource;
        }

        /// <summary>
        /// 距离比较
        /// </summary>
        /// <param name="source"></param>
        /// <param name="target"></param>
        /// <param name="targetDistance"></param>
        /// <returns></returns>
        protected bool DistanceCompare(D3Object source, D3Object target, float targetDistance, bool isIgnoreZ = true)
        {
            return source.Location.GetDistanceTo(target.Location, isIgnoreZ) - targetDistance > 0;
        }

        /// <summary>
        /// 获取Z距离
        /// </summary>
        /// <param name="source"></param>
        /// <param name="target"></param>
        /// <param name="isIgnoreZ"></param>
        /// <returns></returns>
        protected float GetDistanceZ(D3Object source, D3Object target)
        {
            return Math.Abs(source.Location.Z - target.Location.Z);
        }

        /// <summary>
        /// 获取距离
        /// </summary>
        /// <param name="source"></param>
        /// <param name="target"></param>
        /// <param name="isIgnoreZ"></param>
        /// <returns></returns>
        protected float GetDistance(D3Object source, D3Object target, bool isIgnoreZ = true)
        {
            return source.Location.GetDistanceTo(target.Location, isIgnoreZ);
        }

        /// <summary>
        /// 输出信息
        /// </summary>
        /// <param name="message"></param>
        protected void Output(string message)
        {
            if (IsDebug)
            {
                D3Control.output(message);
            }
        }

        /// <summary>
        /// 重载基类退出函数
        /// </summary>
        /// <param name="entity"></param>
        protected override void DoExit(D3Player entity)
        {
            if (PreviousState != null)
            {
                CallChangeStateEvent(entity, PreviousState, false, false);
            }
        }

        #endregion

    }

}

